package com.techshinogongjian.fp.util;

import java.io.File;
import java.util.HashMap;

import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import android.os.Environment;
import android.support.annotation.NonNull;
import android.util.Log;
import android.widget.Toast;

import com.fingerUsb.OnConnectListener;
import com.techshinogongjian.fingerprint.TCFP;
import com.techshinogongjian.fp.client.TcFingerClient;
import com.techshinogongjian.fp.comm.HIDComm;
import com.techshinogongjian.fp.comm.SimpleComm;
import com.techshinogongjian.fp.comm.TwoUsbComm;
import com.techshinogongjian.fp.func.HIDFuncImpl;
import com.techshinogongjian.fp.func.IFingerprintFunc;
import com.techshinogongjian.fp.func.SimpleFuncImpl;
import com.techshinogongjian.fp.func.TwoUsbFuncImpl;

/**
 * usb工具类
 *
 * @author wangzhi
 */
public class USBUtil {

    private static final String TAG = "USBUtil";
    private static final String ACTION_USB_PERMISSION = "com.techshino.fp.ACTION_USB";

    public enum Protocol {
        SIMPLE, HID, TWO
    }
    private Protocol mProtocol = Protocol.SIMPLE;
    public static final int VENDOR_ID0 = 29535; // 这里要改成自己的硬件ID
    public static final int PRODUCT_ID0 = 4865;
    public static final int VENDOR_ID1 = 29535; // 这里要改成自己的硬件ID
    public static final int PRODUCT_ID1 = 4867;
    public static final int VENDOR_ID2 = 29535; // 这里要改成自己的硬件ID
    public static final int PRODUCT_ID2 = 61185;
    public static final int HID_VENDOR_ID = 29535;
    public static final int HID_PRODUCT_ID = 4866;
    private static USBUtil mInstance;
    private Context mContext;
    private UsbManager mUsbManager;
    private UsbDevice mUsbDevice;
    private UsbInterface mInterface;
    private UsbDeviceConnection mDeviceConnection;
    private int mVendorId;
    private int mProductId;
    private UsbEndpoint mEpOut;
    private UsbEndpoint mEpIn;
    private TcFingerClient mClient;
    private IFingerprintFunc mFingerprintFunc;
    private OnConnectListener mConnectListener;
    private TCFP mTcfp;
    private boolean isRegisterMonitor = false;
    private boolean isConnecting = false;
    private boolean isClosing = false;




    private USBUtil(@NonNull Context context) {
        mContext = context;
        mUsbManager = (UsbManager) mContext
                .getSystemService(Context.USB_SERVICE);
        registerMonitor();
    }

    public static USBUtil getInstance(@NonNull Context context) {
        if (mInstance == null) {
            mInstance = new USBUtil(context);
        }
        return mInstance;
    }

    public void setProtocol(Protocol protocol) {
        mProtocol = protocol;
    }

    public void setConnectListener(OnConnectListener connectListener) {
        mConnectListener = connectListener;
    }

    private void registerMonitor() {
        isRegisterMonitor = true;
        // 注册USB设备权限管理广播
        IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
        filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
        filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
        filter.addAction(UsbManager.ACTION_USB_ACCESSORY_ATTACHED);
        filter.addAction(UsbManager.ACTION_USB_ACCESSORY_DETACHED);
        mContext.registerReceiver(usbReceiver, filter);
    }

    public void unRegisterMonitor() {
        if (isRegisterMonitor) {
            mContext.unregisterReceiver(usbReceiver);
        }
    }

    /**
     * 连接设备
     */
    public void connectDevice() {
        Logs.i(TAG, "connectDevice...");
        if (checkDeviceState()) {
            Logs.e(TAG, "1已连接");
            return;
        }
        if (mClient != null && mClient.isConnected()) {
            Logs.e(TAG, "2已连接");
            connected();
            return;
        }

        isConnecting = true;

        registerMonitor();

        enumerateDevice();

        isConnecting = false;
    }

    /**
     * 断开设备
     */
    public void disconnectDevice() {
//        if (checkDeviceState()) {
//            return;
//        }
        isClosing = true;
        if (mDeviceConnection != null) {
            mClient.tcCancel();
            if (mProtocol != Protocol.HID) {
                mDeviceConnection.releaseInterface(mInterface);
            }
            mDeviceConnection.close();
            mDeviceConnection = null;
            mClient = null;
            mFingerprintFunc = null;
            unRegisterMonitor();
        }
        if (mTcfp != null) {
            mTcfp.TCFP_UnInit();
            mTcfp = null;
        }

        isClosing = false;
        Logs.i(TAG, "disconnectDevice...");
    }

    private boolean checkDeviceState() {
        if (isConnecting || isClosing || (mClient != null && mClient.isBusy())) {
            connectFailed("设备忙");
            return true;
        }
        return false;
    }

    /**
     * 枚举设备
     */
    private synchronized void enumerateDevice() {
        Log.e(TAG, "enumerateDevice");

        mUsbManager = (UsbManager) mContext
                .getSystemService(Context.USB_SERVICE);

        HashMap<String, UsbDevice> deviceList = mUsbManager.getDeviceList();

        if (!deviceList.isEmpty()) { // deviceList不为空
            StringBuffer sb = new StringBuffer();
            for (UsbDevice device : deviceList.values()) {
                sb.append(device.toString());
                sb.append("\n");
                // info.setText(sb);
                // 输出设备信息
                Logs.e(TAG, "DeviceInfo: " + device.getVendorId() + " , "
                        + device.getProductId());
                // 枚举到设备
                if (device.getVendorId() == VENDOR_ID0) {
                    openDevice(device);
                    Log.e(TAG, "枚举设备成功");
                }





            }
        }
    }

    /**
     * 找设备接口
     */
    private void findInterface() {
        if (mUsbDevice != null) {
            Logs.d(TAG, "interfaceCounts : " + mUsbDevice.getInterfaceCount());
            for (int i = 0; i < mUsbDevice.getInterfaceCount(); i++) {
                UsbInterface intf = mUsbDevice.getInterface(i);
                if (i == 0) {
                    mInterface = intf; // 保存设备接口
                    Logs.d(TAG, "找到我的设备接口：" + mInterface.getId());
                }
            }
        } else {
            connectFailed("未找到设备");
        }
    }

    /**
     * 分配端点，IN | OUT，即输入输出；此处我直接用1为OUT端点，0为IN，当然你也可以通过判断
     */
    // USB_ENDPOINT_XFER_BULK
    /*
     * #define USB_ENDPOINT_XFER_CONTROL 0 --控制传输 #define USB_ENDPOINT_XFER_ISOC
	 * 1 --等时传输 #define USB_ENDPOINT_XFER_BULK 2 --块传输 #define 3
	 * --中断传输#USB_ENDPOINT_XFER_INT
	 */
    private void assignEndpoint() {
        if (mInterface != null) { // 这一句不加的话 很容易报错 导致很多人在各大论坛问:为什么报错呀
            // 这里的代码替换了一下 按自己硬件属性判断吧
            for (int i = 0; i < mInterface.getEndpointCount(); i++) {
                UsbEndpoint ep = mInterface.getEndpoint(i);
                Logs.i(TAG, "type:" + ep.getType());
                Logs.i(TAG, "direction:" + ep.getDirection());
                if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
                    // setProtocol(Protocol.SIMPLE);
                    if (ep.getDirection() == UsbConstants.USB_DIR_OUT) {
                        mEpOut = ep;
                    } else {
                        mEpIn = ep;
                    }
                }
                if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_INT) {
                    setProtocol(Protocol.HID);
                    if (ep.getDirection() == UsbConstants.USB_DIR_OUT) {
                        mEpOut = ep;
                    } else {
                        mEpIn = ep;
                    }
                }
            }
        }
    }


    /**
     * 打开设备
     */
    private synchronized void openDevice(UsbDevice mUsbDevice) {


        UsbDeviceConnection conn = null;
        // 在open前判断是否有连接权限；对于连接权限可以静态分配，也可以动态分配权限，可以查阅相关资料
        Log.e("openDevice", "openDevice====");
        if (mUsbManager.hasPermission(mUsbDevice)) {
            this.mUsbDevice = mUsbDevice;
            conn = mUsbManager.openDevice(mUsbDevice);
            findInterface();
            assignEndpoint();
            if (conn == null) {
                Log.e(TAG, "打开设备失败");
                connectFailed("打开设备失败");
                return;
            }
            if (conn.claimInterface(mInterface, true)) {
                mDeviceConnection = conn; // 到此你的android设备已经连上HID设备
                Log.e(TAG, "打开设备成功");
                if (mEpIn == null || mEpOut == null) {

                    connectFailed("找不到设备节点");
                    return;
                }
                //Log.e("test","1");
                if (mProtocol == Protocol.SIMPLE) {
                    Logs.i(TAG, "simple...");
                    // FPConfig.setFeatureType(FPConfig.FEATURE_TYPE_V500_GA);
                    //  Log.e("test","2");
                    SimpleComm comm = new SimpleComm(mDeviceConnection, mEpIn,
                            mEpOut);
                    comm.setPid(mUsbDevice.getProductId());
                    mFingerprintFunc = new SimpleFuncImpl(comm);
                    mClient = new TcFingerClient(mFingerprintFunc, mContext);
                    comm.setInitOk(initTCFP());
                } else if (mProtocol == Protocol.TWO) {
                    Logs.i(TAG, "two...");
                    // Log.e("test","3");
                    mFingerprintFunc = new TwoUsbFuncImpl(new TwoUsbComm(
                            mDeviceConnection, mEpIn, mEpOut));

                    mClient = new TcFingerClient(mFingerprintFunc, mContext);
                } else {
                    Logs.i(TAG, "hid...");
                    Log.e("test", "4");
//					FPConfig.setFeatureType(FPConfig.FEATURE_TYPE_BASE64);
                    HIDComm comm = new HIDComm(mDeviceConnection, mEpIn, mEpOut);
                    mFingerprintFunc = new HIDFuncImpl(comm);
                    mClient = new TcFingerClient(mFingerprintFunc, mContext);

                    comm.setInitOk(initTCFP());
                }
                //   Log.e("test","5");
                connected();
            } else {
                Log.e("open fail", "~~~~");
                conn.close();
                return;
            }
        } else {
            PendingIntent intent = PendingIntent.getBroadcast(mContext, 0,
                    new Intent(ACTION_USB_PERMISSION), 0);
            mUsbManager.requestPermission(mUsbDevice, intent);
        }


    }

    /**
     * 初始化算法
     */
    private boolean initTCFP() {
        String path = Environment.getExternalStorageDirectory().getPath()
                + "/TcFingerprintTemp";
        File file = new File(path);
        if (!file.exists()||file.isFile()) {
            file.mkdir();
        }
        // 初始化指纹算法
        int fd = mDeviceConnection.getFileDescriptor();
        if(mTcfp!=null){
            mTcfp.TCFP_UnInit();
            mTcfp = null;
        }
        mTcfp = new TCFP(mContext);
        int code = mTcfp.TCFP_Init(1, fd, path);
        return code == 1;
    }

    private void connected() {
        if (mConnectListener != null) {
            mConnectListener.onConnected(1,mClient,null);
        }
    }

    private void connectFailed(String msg) {
        if (mConnectListener != null) {
            mConnectListener.onConnectFailed(-1, msg);
        }
    }

    private final BroadcastReceiver usbReceiver = new BroadcastReceiver() {

        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();

            if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {

                Log.e("DEVICE_ATTACHED", "---");

                connectDevice();


            }

            if (ACTION_USB_PERMISSION.equals(action)) {
                synchronized (this) {
                    UsbDevice device = (UsbDevice) intent
                            .getParcelableExtra(UsbManager.EXTRA_DEVICE);
                    if (intent.getBooleanExtra(
                            UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                        if (device != null) {
                            openDevice(device);
                        }
                    } else {
                        connectFailed("用户拒绝访问");
                    }
                }
            }
        }
    };

    protected void showTmsg(String string) {
        Toast.makeText(mContext, string, Toast.LENGTH_SHORT).show();
    }
}
